﻿// //  ********************************************************************************
// //  Copyright (C) 2016 Sebastian Kenter. All rights reserved.
// // 
// //  Name    : PhotonServerProject | PhotonServerFramework | ServerPeerFactory.cs
// //  Created : 2016 - 03 - 21 16:43
// //  Modified: 2016 - 04 - 18 09:38
// //  ********************************************************************************

using System;
using ExitGames.Logging;
using NHibernate;
using Photon.SocketServer;
using PhotonServerCommon.Entities.Domain;
using PhotonServerFramework.Implementation.Database;
using PhotonServerFramework.Interfaces.Application;
using PhotonServerFramework.Interfaces.Configuration;
using PhotonServerFramework.Interfaces.Handler;
using PhotonServerFramework.Interfaces.Server;

namespace PhotonServerFramework.Implementation.Server
{
    public class ServerPeerFactory : IServerPeerFactory
    {
        public ILogger Logger { get; }
        private readonly IServerApplication _server;
        private readonly IServerHandlerRegistry _serverHandlerRegistry;
        private readonly IServerPeerRegistry _serverPeerRegistry;

        public ServerPeerFactory(ILogger logger, IServerApplication server, IServerPeerRegistry serverPeerRegistry,
                                 IServerHandlerRegistry serverHandlerRegistry)
        {
            Logger = logger;
            _server = server;
            _serverPeerRegistry = serverPeerRegistry;
            _serverHandlerRegistry = serverHandlerRegistry;
        }

        public T CreateServerPeer<T>(IPeerConfiguration configuration) where T : class
        {
            InitResponse response = configuration.GetConfiguration<InitResponse>();

            if (response != null)
            {
                Logger.InfoFormat("Received init response on port {0} - trying to create a new server peer",
                    response.LocalPort);
                Logger.InfoFormat(
                    "About to create a new server peer (local: {0}:{1}, remote: {2}:{3}, connection: {4}, protocol: {5}, type={6})",
                    response.LocalIP, response.LocalPort, response.RemoteIP, response.RemotePort, response.ConnectionId,
                    response.Protocol.ProtocolType, response.PhotonPeer.GetPeerType().ToString());

                ServerPeer serverPeer = new ServerPeer(response.Protocol, response.PhotonPeer, Logger,
                    _serverHandlerRegistry, _server);

                using (ISession session = SessionManager.OpenSession())
                {
                    using (ITransaction transaction = session.BeginTransaction())
                    {
                        try
                        {
                            ServerPeerT peer = new ServerPeerT
                                               {
                                                   Application = _server.Configuration.Name,
                                                   ConnectionId = response.ConnectionId,
                                                   Connected = 1,
                                                   LocalIp = response.LocalIP,
                                                   LocalPeerId = serverPeer.ServerPeerId.ToString(),
                                                   LocalPort = response.LocalPort,
                                                   LocalServerId = _server.ServerId.ToString(),
                                                   LocalServerType = (int) _server.ServerType,
                                                   Protocol = response.Protocol.ProtocolType.ToString(),
                                                   RemoteIp = response.RemoteIP,
                                                   RemotePeerId = null,
                                                   RemotePort = response.RemotePort,
                                                   RemoteServerId = null,
                                                   RemoteServerType = null,
                                                   DzIns = DateTime.Now,
                                                   DzUpd = DateTime.Now,
                                                   NamUpd = GetType().Name,
                                                   Tsn = 1
                                               };

                            session.Save(peer);
                            transaction.Commit();
                        }
                        catch (Exception ex)
                        {
                            Logger.ErrorFormat("Operation failed with: {0}", ex.Message);
                            transaction.Rollback();
                        }
                    }
                }

                _serverPeerRegistry.RegisterServerPeer(serverPeer);

                serverPeer.ConnectPeer();

                return serverPeer as T;
            }

            Logger.ErrorFormat("Could not create server peer.");

            return null;
        }
    }
}
